/**
 * @file common_func.cpp
 * @brief 
 * @author LiWanglin (lwl510ll@163.com)
 * @version 1.0
 * @date 2024-06-29
 * 
 * @copyright Copyright (c) 2024  LiWanglin
 * 
 * @par 修改日志:
 * <table>
 * <tr><th>Date       <th>Version <th>Author  <th>Description
 * <tr><td>2024-06-29 <td>1.0     <td>wangh     <td>内容
 * </table>
 */



#include "common.h"

extern "C" {
    #include <sys/socket.h>
    #include <arpa/inet.h>
    #include <netinet/in.h>
    #include <unistd.h>
}

#define CM_SOCKET_TYPE_UDP 0
#define CM_SOCKET_TYPE_TCP 1

static int create_socket(int type)
{
    int on = 1;

    int socket_fd = -1;

    switch (type) {
        case CM_SOCKET_TYPE_UDP:
            socket_fd = socket(AF_INET, SOCK_DGRAM, 0);
            break;
        case CM_SOCKET_TYPE_TCP:
            socket_fd = socket(AF_INET, SOCK_STREAM, 0);
            break;
        default:
            break;
    }

    setsockopt(socket_fd, SOL_SOCKET, SO_REUSEADDR, (const char*)&on, sizeof(on));

    return socket_fd;
}

static int bind_socket(int socket_fd, char *ip, uint16_t port)
{
    if(socket_fd < 0) {
        return CM_SOCKET_ERROR;
    }

    if(nullptr == ip) {
        return CM_NULL_POINT;
    }

    if(port <= 0) {
        return CM_ARG_ERROR;
    }

    struct sockaddr_in addr;
    addr.sin_family = AF_INET;
    addr.sin_port = htons(port);
    addr.sin_addr.s_addr = inet_addr(ip);

    if (bind(socket_fd, (struct sockaddr*)&addr, sizeof(addr)) < 0) {
        close(socket_fd);
        return CM_BIND_SOCKET_FAILED;
    }

    return CM_OK;
}

int CMFunc::create_udp_socket(int *fd, char *ip, uint16_t port)
{
    if(nullptr == fd || nullptr == ip) {
        return CM_NULL_POINT;
    }

    int ret = CM_OK;

    int socket_fd = create_socket(CM_SOCKET_TYPE_UDP);
    ret = bind_socket(socket_fd, ip, port);
    if(ret == CM_OK) {
        *fd = socket_fd;
    }

    return ret;
}

int CMFunc::create_tcp_socket(int *fd, char *ip, uint16_t port, bool listen_enable)
{
    if(nullptr == fd || nullptr == ip) {
        return CM_NULL_POINT;
    }

    int ret = CM_OK;

    int socket_fd = create_socket(CM_SOCKET_TYPE_TCP);
    ret = bind_socket(socket_fd, ip, port);
    if(ret == CM_OK) {
        *fd = socket_fd;
    }

    if(listen_enable) {
        ret = listen(socket_fd, 5);
        if(ret < 0) {
            ret = CM_SOCKET_LISTEN_ERR;
        }
    }

    return ret;
}

